<?php
declare(strict_types=1);

namespace Framework\Libs;

use Framework\Service;
use Framework\Support\Request;
use Swoole\Exception;
use Swoole\Http\Response;
use Swoole\Table;
use Swoole\Timer;
use Swoole\WebSocket\Server as WebSocketServer;
use Swoole\Http\Server as HttpServer;
use OSS\Core\OssException;
use OSS\OssClient;
/**
 * //IDE_LOAD_START
 *
 * //IDE_LOAD_END
 */
class Controller extends \stdClass
{

    protected Service $server;
    protected HttpServer|WebSocketServer $http_server;
    protected Event $event;
    protected $_response;
    public bool $not_closed = false;
    public bool $is_ajax = false;
    public string $session_id = '';
    public Request $request ;
    public string $controller = '';
    public string $action = '';
    public array $route = [];
    public array $assign = [];
    public string $_method = '';
    public OssClient $ossClient;
    public function __construct()
    {
        $this->server = $_ENV["bizan"];
        $this->http_server = $this->server->http_server;
        $this->event = new \App\Event();
        $this->ossClient = new OssClient(_CONF('OssAccessKey'), _CONF('OssSecretKey'), _CONF('OssEndpoint'));
    }

    public function _T($name): Table
    {
        // replace table
    }

    public function SetConfig(string $name, int $is_json, array $value): void
    {
        $data = "";
        switch ($is_json) {
            case 1:
                $data = xn_json_encode($value);
                break;
            case 2:
                $data = implode(',', $value);
                break;
        }
        $this->_T("Config")->set($name, ['json' => $is_json, 'value' => $data]);
    }

    public function GetConfig(string $name,mixed $def = ''):string|array
    {
        $data = $this->_T("Config")->get($name);
        $value = $def;
        if (empty($data)) {
            return $value;
        }
        switch ($data['json']) {
            case 1:
                $value = xn_json_decode($data['value']);
                break;
            case 2:
                $value = explode(',', $data['value']);
                break;
            default:
                $value = $data['value'];
        }
        return $value;
    }

    /**
     * @title    table_check
     * @param $key
     * @param int $micro_time 多少毫秒后自动解锁
     * @param string $info 排队[#s]秒还需[#e]秒
     */
    public function table_check(string $key,int $micro_time = 60000,string $info = '排队[#s]秒还需[#e]秒'):void
    {
        $num = $this->_T('TmpLock')->get($key, 'Lock');
        $_time = bcmul((string)get_ut(), "1000", 0);
        $id = 0;
        if (!empty($num) && $num >= $_time) {
            $this->response('0006', [], str_replace(['#s', '#e'], [bcdiv((string)$micro_time, "1000", 2), bcdiv($num - $_time, "1000", 2)], $info));
        }
        $this->_T('TmpLock')->set($key, ['Lock' => bcadd($_time, (string)$micro_time, 0)]);
        if ($micro_time) {
             Timer::after($micro_time, function () use ($key) {
                $this->_T('TmpLock')->set($key, ['Lock' => 0]);
                $this->_T('TmpLock')->del($key);
            });
        }
    }

    /**
     * @title    table_unlock
     *
     * @param     $key
     * @param int $micro_time
     */
    public function table_unlock(string $key, int $micro_time = 0)
    {
        if ($micro_time == 0) {
            $this->_T('TmpLock')->set($key, ['Lock' => 0]);
            $this->_T('TmpLock')->del($key);
        } else {
            Timer::after($micro_time, function () use ($key) {
                $this->_T('TmpLock')->set($key, ['Lock' => 0]);
                $this->_T('TmpLock')->del($key);
            });
        }
    }

    /**
     * User: zhixiang
     * @param $name
     *
     * @return mixed
     */
    public function __get($name)
    {
        // replace models
    }

    //登录验证权限
    public function auth()
    {
        $this->assign['token'] = $this->token;

    }

    public function login()
    {
        $this->assign['token'] = $this->token;
    }

    public function init(string $controller, array $route,string $action, Request $request, Response $response)
    {
        //$controller,$route,$action, $request, $response
        $this->is_ajax = $this->is_ajax ?: $request->is_ajax;
        $this->_method = $request->_S('REQUEST_METHOD');

        $this->assign = [];
        $this->controller = $controller;
        $this->action = $action;
        $this->route = $route;
        $this->_route = implode('_', $route);
        $this->request = $request;
        $this->_response = $response;

        $this->http_host = $request->_S('HTTP_HOST');
        $upload_domain = _CONF('upload_domain');
        $upload_domain = $upload_domain ? $request->_S('SCHEME') . '://' . $upload_domain : $request->_S('HTTP_HOST');
        $this->upload_domain = rtrim($upload_domain, '/');
        array_pop($route);
        $this->index_url = '../../' . implode('/', $route);
        $this->login_url = '../../' . $this->route[0] . '/index/login';

    }

    public function add_header($key, $value)
    {
        $this->_response->header($key, $value);
    }

    public function setcookie($name, $value, $expire = 3600, $httponly = false, $path = '/')
    {
        return $this->_response->cookie(_CONF('cookie_prefixes') . $name, $value, time() + $expire, $path, "", false, $httponly);
    }

    public function set_cookie($name, $value, $expire = 3600, $httponly = false, $path = '/')
    {
        return $this->_response->cookie($name, $value, time() + $expire, $path, "", false, $httponly);
    }


    public function response(string $code = '0000',array $data = [],string $msg = '',string $url = '',int $status = 200,int $json = 0)
    {
        // hook common_response_before.php
        $json = $this->is_ajax ?: $json;
        $_msg = $msg ?: ($_ENV['sys']['ErrorCode'][$code] ?? '操作失败');
        $result = '';
        if ($status == 301 || $status == 302) {
            $result = $url;
        } else {
            // hook common_response_code_before.php

            if ($json == 1 || $status==1000) {
                $result = [
                    'resp_code' => $code,
                    'status' => $status,
                    'msg' => $_msg,
                    'timestamp' => get_microtime(),
                ];

                // hook common_response_data_before.php

                !isset($data['data']) && $data['data'] = [];
                is_array($data) and $result = array_merge($result, $data);
                //is_array($data) and  array_push($result, ...$data);
                // hook common_response_data_json_before.php

                // hook common_response_data_json_after.php
            }
        }
        // hook common_response_after.php
        throw new CustomException($_msg, $status,null,$result);
    }

    //投递异步任务
    public function PostTask($action, $data, $_controller = 'Task\Index'): void
    {

        //return $this->http_server->task_chan->push(['controller'=>$_controller,'action'=>$action,'data'=>$data]);
        \Swoole\Coroutine::create(function () use ($action, $data, $_controller) {
            $this->http_server->task([
                'controller' => $_controller,
                'action' => $action,
                'data' => $data,
            ]);
        });
    }

    /**
     * @param $value
     * @param $text
     *
     * @throws Exception
     * 检测变量是否为空
     */
    public function CheckEmpty($value, $text, $allowZero = true)
    {
        // hook controller_checkempty_start.php
        $i = 0;
        foreach ($value as $k => $val) {
            if (empty($val)) {
                if (is_numeric($val) && $allowZero) {
                    $i++;
                    continue;
                }
                $this->response('0003', [], $text[$i] . '不能为空');
            }
            $i++;
        }
        // hook controller_checkempty_end.php
    }

}

?>